package decaf;

/***********************************
* Name: DecafParser.java
* Date: Aug 17, 2010
* @author martin
* Description:
* Licensed Material - Property of Matthew Hawkins (hawkini@4email.net)
***********************************/

import interCodeGen.*;
import asmCodeGen.*;
import java.io.*;
import goldengine.java.*;
import java.util.LinkedList;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTree;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;

public class DecafParser implements GPMessageConstants
{

    private interface SymbolConstants
    {
        final int SYMBOL_EOF                   =  0;  // (EOF)
        final int SYMBOL_ERROR                 =  1;  // (Error)
        final int SYMBOL_WHITESPACE            =  2;  // (Whitespace)
        final int SYMBOL_COMMENTEND            =  3;  // (Comment End)
        final int SYMBOL_COMMENTLINE           =  4;  // (Comment Line)
        final int SYMBOL_COMMENTSTART          =  5;  // (Comment Start)
        final int SYMBOL_MINUS                 =  6;  // '-'
        final int SYMBOL_EXCLAM                =  7;  // '!'
        final int SYMBOL_EXCLAMEQ              =  8;  // '!='
        final int SYMBOL_PERCENT               =  9;  // '%'
        final int SYMBOL_AMPAMP                = 10;  // '&&'
        final int SYMBOL_LPARAN                = 11;  // '('
        final int SYMBOL_RPARAN                = 12;  // ')'
        final int SYMBOL_TIMES                 = 13;  // '*'
        final int SYMBOL_COMMA                 = 14;  // ','
        final int SYMBOL_DOT                   = 15;  // '.'
        final int SYMBOL_DIV                   = 16;  // '/'
        final int SYMBOL_SEMI                  = 17;  // ';'
        final int SYMBOL_LBRACKET              = 18;  // '['
        final int SYMBOL_RBRACKET              = 19;  // ']'
        final int SYMBOL_LBRACE                = 20;  // '{'
        final int SYMBOL_PIPEPIPE              = 21;  // '||'
        final int SYMBOL_RBRACE                = 22;  // '}'
        final int SYMBOL_PLUS                  = 23;  // '+'
        final int SYMBOL_LT                    = 24;  // '<'
        final int SYMBOL_LTEQ                  = 25;  // '<='
        final int SYMBOL_EQ                    = 26;  // '='
        final int SYMBOL_EQEQ                  = 27;  // '=='
        final int SYMBOL_GT                    = 28;  // '>'
        final int SYMBOL_GTEQ                  = 29;  // '>='
        final int SYMBOL_BOOLEAN               = 30;  // boolean
        final int SYMBOL_CHAR                  = 31;  // char
        final int SYMBOL_CHARACTER             = 32;  // character
        final int SYMBOL_CLASS                 = 33;  // class
        final int SYMBOL_ELSE                  = 34;  // else
        final int SYMBOL_FALSE                 = 35;  // false
        final int SYMBOL_ID                    = 36;  // id
        final int SYMBOL_IF                    = 37;  // if
        final int SYMBOL_INT                   = 38;  // int
        final int SYMBOL_NUM                   = 39;  // num
        final int SYMBOL_PROGRAM               = 40;  // Program
        final int SYMBOL_RETURN                = 41;  // return
        final int SYMBOL_STRUCT                = 42;  // struct
        final int SYMBOL_TRUE                  = 43;  // true
        final int SYMBOL_VOID                  = 44;  // void
        final int SYMBOL_WHILE                 = 45;  // while
        final int SYMBOL_ADDEXP                = 46;  // <Add Exp>
        final int SYMBOL_ADDOP                 = 47;  // <addop>
        final int SYMBOL_ARG                   = 48;  // <arg>
        final int SYMBOL_ARGLIST               = 49;  // <arg list>
        final int SYMBOL_ASSIGN                = 50;  // <assign>
        final int SYMBOL_BLOCK                 = 51;  // <block>
        final int SYMBOL_BOOL_LITERAL          = 52;  // <bool_literal>
        final int SYMBOL_CHAR_LITERAL          = 53;  // <char_literal>
        final int SYMBOL_CONDITIONALOP         = 54;  // <conditionalop>
        final int SYMBOL_DECLARATION           = 55;  // <declaration>
        final int SYMBOL_EXPRESSION            = 56;  // <expression>
        final int SYMBOL_INT_LITERAL           = 57;  // <int_literal>
        final int SYMBOL_ITERATION             = 58;  // <iteration>
        final int SYMBOL_KLEENE_DECLARATION    = 59;  // <kleene_declaration>
        final int SYMBOL_KLEENE_STATEMENT      = 60;  // <kleene_statement>
        final int SYMBOL_KLEENE_VARDECLARATION = 61;  // <kleene_varDeclaration>
        final int SYMBOL_LITERAL               = 62;  // <literal>
        final int SYMBOL_LOCATION              = 63;  // <location>
        final int SYMBOL_METHODCALL            = 64;  // <methodCall>
        final int SYMBOL_METHODDECLARATION     = 65;  // <methodDeclaration>
        final int SYMBOL_MULOP                 = 66;  // <mulop>
        final int SYMBOL_MULTEXP               = 67;  // <Mult Exp>
        final int SYMBOL_NEGATEEXP             = 68;  // <Negate Exp>
        final int SYMBOL_OPT_ARG_SEPARATED     = 69;  // <opt_arg_separated>
        final int SYMBOL_OPT_ELSE_BLOCK        = 70;  // <opt_else_block>
        final int SYMBOL_OPT_EXPRESSION        = 71;  // <opt_expression>
        final int SYMBOL_OPT_PARAMETER         = 72;  // <opt_parameter>
        final int SYMBOL_PARAMETER             = 73;  // <parameter>
        final int SYMBOL_PARAMETERLIST         = 74;  // <parameter list>
        final int SYMBOL_PROGRAM2              = 75;  // <Program>
        final int SYMBOL_RELEXP                = 76;  // <Rel Exp>
        final int SYMBOL_RELOP                 = 77;  // <relop>
        final int SYMBOL_RETURN2               = 78;  // <return>
        final int SYMBOL_SELECTION             = 79;  // <selection>
        final int SYMBOL_SIMPLELOCATION        = 80;  // <simpleLocation>
        final int SYMBOL_STATEMENT             = 81;  // <statement>
        final int SYMBOL_STRUCTDECLARATION     = 82;  // <structDeclaration>
        final int SYMBOL_TYPE                  = 83;  // <Type>
        final int SYMBOL_VALUE                 = 84;  // <Value>
        final int SYMBOL_VARDECL1              = 85;  // <varDecl 1>
        final int SYMBOL_VARDECLARATION        = 86;  // <varDeclaration>
    };

    public interface RuleConstants{
       final int RULE_PROGRAM_CLASS_PROGRAM_LBRACE_RBRACE       =  0;  // <Program> ::= class Program '{' <kleene_declaration> '}'
       final int RULE_KLEENE_DECLARATION                        =  1;  // <kleene_declaration> ::= <declaration> <kleene_declaration>
       final int RULE_KLEENE_DECLARATION2                       =  2;  // <kleene_declaration> ::= 
       final int RULE_DECLARATION                               =  3;  // <declaration> ::= <structDeclaration>
       final int RULE_DECLARATION2                              =  4;  // <declaration> ::= <varDeclaration>
       final int RULE_DECLARATION3                              =  5;  // <declaration> ::= <methodDeclaration>
       final int RULE_VARDECLARATION_ID_SEMI                    =  6;  // <varDeclaration> ::= <Type> id <varDecl 1> ';'
       final int RULE_VARDECL1_LBRACKET_NUM_RBRACKET            =  7;  // <varDecl 1> ::= '[' num ']'
       final int RULE_VARDECL1                                  =  8;  // <varDecl 1> ::= 
       final int RULE_STRUCTDECLARATION_STRUCT_ID_LBRACE_RBRACE =  9;  // <structDeclaration> ::= struct id '{' <kleene_varDeclaration> '}'
       final int RULE_KLEENE_VARDECLARATION                     = 10;  // <kleene_varDeclaration> ::= <varDeclaration> <kleene_varDeclaration>
       final int RULE_KLEENE_VARDECLARATION2                    = 11;  // <kleene_varDeclaration> ::= 
       final int RULE_METHODDECLARATION_ID_LPARAN_RPARAN        = 12;  // <methodDeclaration> ::= <Type> id '(' <opt_parameter> ')' <block>
       final int RULE_OPT_PARAMETER                             = 13;  // <opt_parameter> ::= <parameter list>
       final int RULE_OPT_PARAMETER2                            = 14;  // <opt_parameter> ::= 
       final int RULE_PARAMETERLIST                             = 15;  // <parameter list> ::= <parameter>
       final int RULE_PARAMETERLIST_COMMA                       = 16;  // <parameter list> ::= <parameter list> ',' <parameter>
       final int RULE_TYPE_INT                                  = 17;  // <Type> ::= int
       final int RULE_TYPE_CHAR                                 = 18;  // <Type> ::= char
       final int RULE_TYPE_BOOLEAN                              = 19;  // <Type> ::= boolean
       final int RULE_TYPE_VOID                                 = 20;  // <Type> ::= void
       final int RULE_TYPE_STRUCT_ID                            = 21;  // <Type> ::= struct id
       final int RULE_TYPE                                      = 22;  // <Type> ::= <structDeclaration>
       final int RULE_PARAMETER_ID                              = 23;  // <parameter> ::= <Type> id
       final int RULE_PARAMETER_ID_LBRACKET_RBRACKET            = 24;  // <parameter> ::= <Type> id '[' ']'
       final int RULE_BLOCK_LBRACE_RBRACE                       = 25;  // <block> ::= '{' <kleene_varDeclaration> <kleene_statement> '}'
       final int RULE_KLEENE_STATEMENT                          = 26;  // <kleene_statement> ::= <statement> <kleene_statement>
       final int RULE_KLEENE_STATEMENT2                         = 27;  // <kleene_statement> ::= 
       final int RULE_STATEMENT                                 = 28;  // <statement> ::= <block>
       final int RULE_STATEMENT2                                = 29;  // <statement> ::= <selection>
       final int RULE_STATEMENT3                                = 30;  // <statement> ::= <iteration>
       final int RULE_STATEMENT_SEMI                            = 31;  // <statement> ::= <return> ';'
       final int RULE_STATEMENT_SEMI2                           = 32;  // <statement> ::= <assign> ';'
       final int RULE_STATEMENT_SEMI3                           = 33;  // <statement> ::= <opt_expression> ';'
       final int RULE_SELECTION_IF_LPARAN_RPARAN                = 34;  // <selection> ::= if '(' <expression> ')' <block> <opt_else_block>
       final int RULE_OPT_ELSE_BLOCK_ELSE                       = 35;  // <opt_else_block> ::= else <block>
       final int RULE_OPT_ELSE_BLOCK                            = 36;  // <opt_else_block> ::= 
       final int RULE_ITERATION_WHILE_LPARAN_RPARAN             = 37;  // <iteration> ::= while '(' <expression> ')' <block>
       final int RULE_RETURN_RETURN                             = 38;  // <return> ::= return <opt_expression>
       final int RULE_ASSIGN_EQ                                 = 39;  // <assign> ::= <location> '=' <expression>
       final int RULE_OPT_EXPRESSION                            = 40;  // <opt_expression> ::= <expression>
       final int RULE_OPT_EXPRESSION2                           = 41;  // <opt_expression> ::= 
       final int RULE_EXPRESSION                                = 42;  // <expression> ::= <Rel Exp> <conditionalop> <expression>
       final int RULE_EXPRESSION2                               = 43;  // <expression> ::= <Rel Exp>
       final int RULE_RELEXP                                    = 44;  // <Rel Exp> ::= <Add Exp> <relop> <Rel Exp>
       final int RULE_RELEXP2                                   = 45;  // <Rel Exp> ::= <Add Exp>
       final int RULE_ADDEXP                                    = 46;  // <Add Exp> ::= <Mult Exp> <addop> <Add Exp>
       final int RULE_ADDEXP2                                   = 47;  // <Add Exp> ::= <Mult Exp>
       final int RULE_MULTEXP                                   = 48;  // <Mult Exp> ::= <Negate Exp> <mulop> <Mult Exp>
       final int RULE_MULTEXP2                                  = 49;  // <Mult Exp> ::= <Negate Exp>
       final int RULE_NEGATEEXP_MINUS                           = 50;  // <Negate Exp> ::= '-' <Value>
       final int RULE_NEGATEEXP_EXCLAM                          = 51;  // <Negate Exp> ::= '!' <Value>
       final int RULE_NEGATEEXP                                 = 52;  // <Negate Exp> ::= <Value>
       final int RULE_CONDITIONALOP_AMPAMP                      = 53;  // <conditionalop> ::= '&&'
       final int RULE_CONDITIONALOP_PIPEPIPE                    = 54;  // <conditionalop> ::= '||'
       final int RULE_RELOP_LTEQ                                = 55;  // <relop> ::= '<='
       final int RULE_RELOP_LT                                  = 56;  // <relop> ::= '<'
       final int RULE_RELOP_GT                                  = 57;  // <relop> ::= '>'
       final int RULE_RELOP_GTEQ                                = 58;  // <relop> ::= '>='
       final int RULE_RELOP_EQEQ                                = 59;  // <relop> ::= '=='
       final int RULE_RELOP_EXCLAMEQ                            = 60;  // <relop> ::= '!='
       final int RULE_ADDOP_PLUS                                = 61;  // <addop> ::= '+'
       final int RULE_ADDOP_MINUS                               = 62;  // <addop> ::= '-'
       final int RULE_MULOP_TIMES                               = 63;  // <mulop> ::= '*'
       final int RULE_MULOP_DIV                                 = 64;  // <mulop> ::= '/'
       final int RULE_MULOP_PERCENT                             = 65;  // <mulop> ::= '%'
       final int RULE_VALUE                                     = 66;  // <Value> ::= <literal>
       final int RULE_VALUE_LPARAN_RPARAN                       = 67;  // <Value> ::= '(' <expression> ')'
       final int RULE_VALUE2                                    = 68;  // <Value> ::= <methodCall>
       final int RULE_VALUE3                                    = 69;  // <Value> ::= <location>
       final int RULE_LOCATION_DOT                              = 70;  // <location> ::= <simpleLocation> '.' <location>
       final int RULE_LOCATION                                  = 71;  // <location> ::= <simpleLocation>
       final int RULE_SIMPLELOCATION_ID_LBRACKET_RBRACKET       = 72;  // <simpleLocation> ::= id '[' <expression> ']'
       final int RULE_SIMPLELOCATION_ID                         = 73;  // <simpleLocation> ::= id
       final int RULE_METHODCALL_ID_LPARAN_RPARAN               = 74;  // <methodCall> ::= id '(' <opt_arg_separated> ')'
       final int RULE_OPT_ARG_SEPARATED                         = 75;  // <opt_arg_separated> ::= <arg list>
       final int RULE_OPT_ARG_SEPARATED2                        = 76;  // <opt_arg_separated> ::= 
       final int RULE_ARGLIST                                   = 77;  // <arg list> ::= <arg>
       final int RULE_ARGLIST_COMMA                             = 78;  // <arg list> ::= <arg list> ',' <arg>
       final int RULE_ARG                                       = 79;  // <arg> ::= <expression>
       final int RULE_LITERAL                                   = 80;  // <literal> ::= <int_literal>
       final int RULE_LITERAL2                                  = 81;  // <literal> ::= <char_literal>
       final int RULE_LITERAL3                                  = 82;  // <literal> ::= <bool_literal>
       final int RULE_INT_LITERAL_NUM                           = 83;  // <int_literal> ::= num
       final int RULE_CHAR_LITERAL_CHARACTER                    = 84;  // <char_literal> ::= character
       final int RULE_BOOL_LITERAL_TRUE                         = 85;  // <bool_literal> ::= true
       final int RULE_BOOL_LITERAL_FALSE                        = 86;  // <bool_literal> ::= false
    };

    public DecafParser(){}

    /*****************************************
     * @return the root
     *****************************************/
    public DefaultMutableTreeNode getRoot() {
        return root;
    }

    /*****************************************
     * @return the arbol
     *****************************************/
    public JTree getJTree() {
        return this.jtree;
    }

    /*****************************************
     * @return the table
     *****************************************/
    public SymbolTable getSymbolTable() {
        return symboltable;
    }

    /*****************************************
     * @return the table
     *****************************************/
    public StructTable getStructTable() {
        return this.structTable;
    }

    /*****************************************
     * @return the table
     *****************************************/
    public MethodTable getMethodTable() {
        return this.methodTable;
    }

    /*****************************************
     * @return the error
     *****************************************/
    public boolean isError() {
        return error;
    }

    /*****************************************
     * @return the error_log
     *****************************************/
    public String getError_log() {
        return error_log;
    }

    /*****************************************
     * @return the debug_log
     *****************************************/
    public String getDebug_log() {
        return debug_log;
    }

    /*****************************************
     * @return the output_log
     *****************************************/
    public String getOutput_log() {
        return output_log;
    }

    public void All(){
        //GOLDParser parser = new GOLDParser();
        parser.setTrimReductions(false);
        try{
            parser.loadCompiledGrammar(this.compiledGrammar);
            parser.openFile(textToParse);
        }
       catch(ParserException parse){

           println("**PARSER ERROR**\n" + parse.toString());
           this.addErrorLog("** PARSER ERROR ** "+"\n\t"+ parse.toString() +"\n");
       }

       boolean done = false;
       int response = -1;

       while(!done)
       {
           try{
               response = parser.parse();
           }
           catch(ParserException parse){
               println("**PARSER ERROR**\n" + parse.toString());
               this.addErrorLog("** PARSER ERROR ** "+"\n\t"+ parse.toString() +"\n");
           }

           switch(response)
           {
               case gpMsgTokenRead:
                   /* A token was read by the parser. The Token Object can be accessed
                      through the CurrentToken() property:  Parser.CurrentToken */
                   parser.currentToken().setLineNumber(parser.currentLineNumber());
                   break;

               case gpMsgReduction:
                   /* This message is returned when a rule was reduced by the parse engine.
                      The CurrentReduction property is assigned a Reduction object
                      containing the rule and its related tokens. You can reassign this
                      property to your own customized class. If this is not the case,
                      this message can be ignored and the Reduction object will be used
                      to store the parse tree.  */
                   Reduction reduction  = parser.currentReduction();
                    //Parser.Reduction = //Object you created to store the rule
                    // ************************************** log file
                    //println("gpMsgReduction");
                    Reduction myRed = parser.currentReduction();
                    //this.addDebugLog("gpMsgReduction (Line "+parser.currentLineNumber()+"): "+"\n\t"+ myRed.getParentRule().getText() +"\n");
                    //println(myRed.getParentRule().getText());
                    // ************************************** end log
                    break;
                case gpMsgAccept:
                    /* The program was accepted by the parsing engine */
                    // ************************************** log file
                    this.error = false;
                    this.addOutputLog("gpMsgAccept");
                    println("gpMsgAccept");
                    // ************************************** end log
                    done = true;
                    break;
                case gpMsgLexicalError:
                    /* Place code here to handle a illegal or unrecognized token
                           To recover, pop the token from the stack: Parser.PopInputToken */
                    // ************************************** log file
                    Token token = parser.popInputToken();
                    this.addErrorLog("gpMsgLexicalError (Line "+parser.currentLineNumber()+"): " +"\n\tIllegal or unrecognized token: "+ (String)token.getData());
                    println("gpMsgLexicalError");
                    // ************************************** end log
                    done = true;
                    break;
                case gpMsgNotLoadedError:
                    /* Load the Compiled Grammar Table file first. */
                    // ************************************** log file
                    this.addErrorLog("gpMsgNotLoadedError (Line "+parser.currentLineNumber()+"): " +"\n\t"+ "Load the Compiled Grammar Table file first.");
                    println("gpMsgNotLoadedError");
                    // ************************************** end log
                    done = true;
                    break;
                case gpMsgSyntaxError:
                    /* This is a syntax error: the source has produced a token that was
                           not expected by the LALR State Machine. The expected tokens are stored
                           into the Tokens() list. To recover, push one of the
                              expected tokens onto the parser's input queue (the first in this case):
                           You should limit the number of times this type of recovery can take
                           place. */
                    done = true;
                    Token theTok = parser.currentToken();
                    println("Token not expected: " + (String)theTok.getData());
                    // ************************************** log file
                    this.addErrorLog("gpMsgSyntaxError (Line "+parser.currentLineNumber()+"): " +"\n\t"+ "Token not expected: "+ (String)theTok.getData());
                    println("gpMsgSyntaxError");
                    // ************************************** end log
                    break;
                case gpMsgCommentError:
                    /* The end of the input was reached while reading a comment.
                             This is caused by a comment that was not terminated */
                    // ************************************** log file
                    this.addErrorLog("gpMsgCommentError (Line "+parser.currentLineNumber()+"): " +"\n\t"+ "The end of the input was reached while reading a comment.");
                    println("gpMsgCommentError");
                    // ************************************** end log
                    done = true;
                    break;
                case gpMsgInternalError:
                    /* Something horrid happened inside the parser. You cannot recover */
                    // ************************************** log file
                    this.addErrorLog("gpMsgInternalError (Line "+parser.currentLineNumber()+"): " +"\n\t"+ "Something horrid happened inside the parser. You cannot recover");
                    println("gpMsgInternalError");
                    // ************************************** end log
                    done = true;
                    break;
            }
        }
    }

    /***************************************************************
    * showTree
    * recursive method to generate the JTree
    * @param tree
    * @param root
    * @param reduction
    ***************************************************************/
    public void showTree(DefaultTreeModel tree, DefaultMutableTreeNode root, Reduction reduccion){
        
        for(int i=0; i<reduccion.getTokenCount(); i++)
        {
            if(reduccion.getToken(i).getKind()==0){
                //Here comes when there is a non terminal. Example: <a> ::= 'b' <a> | 'c'
                Reduction red = (Reduction)reduccion.getToken(i).getData();
                String rule = red.getParentRule().definition();
                String rule_name = reduccion.getToken(i).getName();
                //println(" + "+rule_name+ " + ."+rule+".");
                DefaultMutableTreeNode child = new DefaultMutableTreeNode(reduccion.getToken(i).getName());
                showTree(tree, child, (Reduction)reduccion.getToken(i).getData());
                tree.insertNodeInto(child, root, i);
            }

            else{
                // Here comes when there is a terminal -> token
                // Token -> (name token, token lexeme)
                // This will be a leaf
                String token_name = reduccion.getToken(i).getName();
                String token_lexeme = (String)reduccion.getToken(i).getData();
                String txt_in_leaf = "";
                if(token_name.equals(token_lexeme) == true && token_name.equals("id")==false){
                    txt_in_leaf = token_name+"";
                }
                else{
                    txt_in_leaf = token_name + " = "+ token_lexeme;
                }
                //println(" - "+txt_in_leaf);
                DefaultMutableTreeNode leaf = new DefaultMutableTreeNode(txt_in_leaf);
                tree.insertNodeInto(leaf, root, i);
            }
        }
    }

    /***************************************************************
    * getParamList
    * recursive method to generate symbolTable
    * @param reduction
    ***************************************************************/
    private LinkedList<Symbol> getParamList(Reduction reduction){

        LinkedList<Symbol> list = new LinkedList<Symbol>();
        String id = "";
        Reduction type = null;
        switch(reduction.getParentRule().getTableIndex())
        {
            case RuleConstants.RULE_OPT_PARAMETER:
                //#########################################################################################################
                //<opt_parameter> ::= <parameter list>
                list.addAll(getParamList((Reduction)reduction.getToken(0).getData()));
                break;
            case RuleConstants.RULE_OPT_PARAMETER2:
                //#########################################################################################################
                //<opt_parameter> ::=
                break;
            case RuleConstants.RULE_PARAMETERLIST_COMMA:
                //#########################################################################################################
                //<parameter list> ::= <parameter list> ',' <parameter>
                list.addAll(getParamList((Reduction)reduction.getToken(0).getData()));
                list.addAll(getParamList((Reduction)reduction.getToken(2).getData()));
                break;
            case RuleConstants.RULE_PARAMETERLIST:
                //#########################################################################################################
                //<parameter list> ::= <parameter>
                list.addAll(getParamList((Reduction)reduction.getToken(0).getData()));
                break;
            case RuleConstants.RULE_PARAMETER_ID: case RuleConstants.RULE_PARAMETER_ID_LBRACKET_RBRACKET:
                //#########################################################################################################
                //<parameter> ::= <Type> id | <Type> id '[' ']'
                //<Type> = <parameterType> ::= 'int' | 'char' | 'boolean'
                type = (Reduction) reduction.getToken(0).getData();
                id = (String) reduction.getToken(1).getData();
                Type tipo = null;
                if(type.getToken(0).getData() instanceof String){
                    String a = (String)type.getToken(0).getData();
                    if(a.equals("int") || a.equals("char") || a.equals("boolean")){
                        //TODO verificar tamaños de los tipos
                        tipo = new Type(a,Type.getBasicTamano(a));
                        tipo.setParam(true);
                    }else{
                        this.addErrorLog("\nParameter type not correct (Line "+type.getToken(0).getLineNumber()+"): "+(String)type.getToken(0).getData()+" -> "+id+"");
                        break;
                    }
                }else{
                    this.addErrorLog("\nParameter type not correct (Line "+type.getToken(0).getLineNumber()+"): "+type.getToken(0).getName()+" -> "+id+"");
                    break;
                }
                if(reduction.getTokenCount()==4){
                    tipo.setArray(true);
                }
                Symbol simb = new Symbol(id, tipo, this.actual_ambit);
                list.add(simb);
                break;
        }
        return list;
    }

    /***************************************************************
    * getMembersList
    * recursive method to generate SymbolTable
    * @param reduction
    ***************************************************************/
    private LinkedList<Symbol> getMembersList(Reduction reduction){

        LinkedList<Symbol> list = new LinkedList<Symbol>();
        Type type = null;

        switch(reduction.getParentRule().getTableIndex())
        {
            case RuleConstants.RULE_KLEENE_VARDECLARATION:
                //#########################################################################################################
                //<kleene_varDeclaration> ::= <varDeclaration> <kleene_varDeclaration>
                list.addAll(this.getMembersList((Reduction)reduction.getToken(0).getData()));
                list.addAll(this.getMembersList((Reduction)reduction.getToken(1).getData()));
                break;
            case RuleConstants.RULE_KLEENE_VARDECLARATION2:
                //#########################################################################################################
                //<kleene_varDeclaration> ::=
                break;
            case RuleConstants.RULE_VARDECLARATION_ID_SEMI:
                //#########################################################################################################
                //<varDeclaration> ::= <Type> id <varDecl 1> ';'
                String id_varDecl = (String)reduction.getToken(1).getData();
                Reduction var_decl_1 = (Reduction)reduction.getToken(2).getData();
                Reduction Type1 =(Reduction)reduction.getToken(0).getData();
                int num_type = (Type1).getParentRule().getTableIndex();
                //*************************************************************************************************************
                if(num_type == RuleConstants.RULE_TYPE_INT || num_type == RuleConstants.RULE_TYPE_CHAR || num_type == RuleConstants.RULE_TYPE_BOOLEAN){
                    //---------------------------------------------------------------------------------------------------------
                    //<Type> ::= int | char | boolean
                    
                    String a = (String)Type1.getToken(0).getData();
                    
                    //TODO verificar tamaños de los tipos
                    type = new Type(a,Type.getBasicTamano(a));
                    type.setSimple(true);
                }
                else if(num_type == RuleConstants.RULE_TYPE_VOID){
                    //---------------------------------------------------------------------------------------------------------
                    //<Type> ::= void
                    this.addErrorLog("\nCan't define a void type inside a structure (Line "+Type1.getToken(0).getLineNumber()+"): "+Type1.getToken(0).getData()+"");
                }
                else if(num_type == RuleConstants.RULE_TYPE_STRUCT_ID){
                    //---------------------------------------------------------------------------------------------------------
                    //<Type> ::= struct id
                    String id = (String)Type1.getToken(1).getData();
                    Structure struct = this.structTable.getStructure(id, actual_ambit);
                    if(struct == null){
                        this.addErrorLog("\nStruct type not defined (Line "+Type1.getToken(1).getLineNumber()+"): struct "+id+"");
                    }else{
                        type = struct.getType();
                    }
                }
                else if(num_type == RuleConstants.RULE_TYPE){
                    //---------------------------------------------------------------------------------------------------------
                    //<Type> ::= <structDeclaration>
                    //TODO revisar si se puede definir un struct decl dentro del structDecl
                    //type = this.getTypeStructDecl((Reduction)reduction.getToken(0).getData());
                    this.addErrorLog("\nA struct declaration cannot have a struct declaration inside (Line "+reduction.getToken(0).getLineNumber()+"): "+reduction.getToken(0).getData()+"");
                }
                //*************************************************************************************************************
                //<varDecl 1> ::= '[' num ']' |
                if(type!=null){
                    if(var_decl_1.getTokenCount()==3){
                        int num = Integer.parseInt((String)var_decl_1.getToken(1).getData());
                        if(num==0){
                            this.addErrorLog("\nArray length must be larger than 0 (Line "+reduction.getToken(1).getLineNumber()+")");
                            break;
                        }
                        type.setArray(true, num);
                    }
                    Symbol symbol = new Symbol(id_varDecl,type,this.actual_ambit);
                    list.add(symbol);
                }
                
                break;
        }
        return list;
    }

    /***************************************************************
    * getStructDecl
    * @param reduction
    ***************************************************************/
    private Structure getStructDecl(Reduction reduction){
        //<structDeclaration> ::= struct id '{' <kleene_varDeclaration> '}'
        String id = (String)reduction.getToken(1).getData();
        Reduction kleene_varDecl = (Reduction)reduction.getToken(3).getData();
        LinkedList<Symbol> members = new LinkedList<Symbol>();
        members = this.getMembersList(kleene_varDecl);

        Structure struct = new Structure(id, this.actual_ambit, members);
        return struct;
    }

    /***************************************************************
    * getType
    * @param reduction
    * @return Type
    * Obtains the type
    ***************************************************************/
    private Type getType(Reduction reduction) {
        Type type = null;
        //*************************************************************************************************************
        switch(reduction.getParentRule().getTableIndex())
        {
            case RuleConstants.RULE_TYPE_INT: case RuleConstants.RULE_TYPE_CHAR: case RuleConstants.RULE_TYPE_BOOLEAN: case RuleConstants.RULE_TYPE_VOID:
                //#########################################################################################################
                //<Type> ::= int | char | boolean | void
                //System.out.println("\ttipo básico");
                
                String a = (String)reduction.getToken(0).getData();
                type = new Type(a,Type.getBasicTamano(a));
                type.setSimple(true);
                break;
            case RuleConstants.RULE_TYPE_STRUCT_ID:
                //#########################################################################################################
                //<Type> ::= struct id
                //System.out.println("\tStruct type - sin declarar");
                String id = (String) reduction.getToken(1).getData();

                boolean exist = (this.structTable.getStructure(id, actual_ambit) != null);
                if(exist){

                    //type = this.symboltable.getTypeStruct(id, actual_ambit);
                    //type.setStructure(true);
                    type = this.structTable.getStructure(id, actual_ambit).getType();
                    
                }
                else{
                    this.addErrorLog("\nStruct type not defined(Line "+reduction.getToken(1).getLineNumber()+"): struct "+id+"");
                }
                break;
            case RuleConstants.RULE_TYPE:
                //#########################################################################################################
                //<Type> ::= <structDeclaration>
                //System.out.println("\tStruct type - declarando");
                boolean added = addStructToStructTable((Reduction)reduction.getToken(0).getData());
                if(added){
                    type = this.structTable.getLastStruct().getType();
                }
                
                break;
        }
        //*************************************************************************************************************
        return type;
    }

    /***************************************************************
    * addStructToStructTable
    * @param reduction
    * @return void
    ***************************************************************/
    private boolean addStructToStructTable(Reduction reduction) {
        //#########################################################################################################
        //<structDeclaration> ::= struct id '{' <kleene_varDeclaration> '}'
        Structure stuct = this.getStructDecl(reduction);
        if(stuct == null){
            this.addErrorLog("\nNull Struct(Line "+reduction.getToken(1).getLineNumber()+"): struct "+((String)reduction.getToken(1).getData())+"");
            return false;
        }
        boolean canAdd = this.structTable.addStructure(stuct);

        if(!canAdd){
            this.addErrorLog("\nStruct already exist (Line "+reduction.getToken(1).getLineNumber()+"): struct "+((String)reduction.getToken(1).getData())+"");
        }
        this.addDebugLog("New Struct declaration (Line "+reduction.getToken(1).getLineNumber()+"): struct "+stuct.getId()+"\n");
        return canAdd;
    }

    /***************************************************************
    * addVarDeclarationToTable
    * @param reduction
    * @return void
    ***************************************************************/
    private void addVarDeclarationToTable(Reduction reduction) {
        //<varDeclaration> ::= <Type> id <varDecl 1> ';'
        //<varDecl 1> ::= '[' num ']' |
        String id_lexeme = (String)reduction.getToken(1).getData();
        Reduction varType = (Reduction)reduction.getToken(0).getData();

        Type type = this.getType(varType);
        if(type == null){
            return;
        }
        boolean already_exist = this.symboltable.existSymbolInScope(id_lexeme, actual_ambit);
        
        if(already_exist){
            this.addErrorLog("\nInvalid Var declaration (Line "+reduction.getToken(1).getLineNumber()+"): var name already exist: "+id_lexeme+"");
            return;
        }
        Reduction varDecl_1 = (Reduction)reduction.getToken(2).getData();
        Symbol var_symbol = new Symbol(id_lexeme, type, this.actual_ambit);

        if(varDecl_1.getTokenCount()==3){
            int num = Integer.parseInt((String)varDecl_1.getToken(1).getData());
            if(num==0){
                this.addErrorLog("\nArray length must be larger than 0 (Line "+varDecl_1.getToken(1).getLineNumber()+")");
                return;
            }
            var_symbol.getType().setArray(true, num);
            var_symbol.getType().setSimple(false);
        }
        this.symboltable.addSymbol(var_symbol);
        this.addDebugLog("New Var declaration (Line "+reduction.getToken(1).getLineNumber()+"): "+id_lexeme+"\n");

    }

    /***************************************************************
    * existLocation_in_Member
    * @param location
    * @param members
    * @return boolean
    ***************************************************************/
    private boolean existLocation_in_Member(String location, LinkedList<Symbol> members) {
        boolean exist = false;

        for(Symbol a : members){
            if(location.equals(a.getId())){
                exist = true;
                break;
            }
        }

        return exist;
    }

    /***************************************************************
    * existLocation_in_Member
    * @param location
    * @param members
    * @return boolean
    ***************************************************************/
    private Symbol getLocation_in_Member(String location, LinkedList<Symbol> members) {

        for(Symbol a : members){
            if(location.equals(a.getId())){
                return a;
            }
        }

        return null;
    }

    /***************************************************************
    * getMethodCallSignature
    * @param reduction
    * @return void
    ***************************************************************/
    public String getMethodCallSignature(Reduction reduction) {
        //<methodCall> ::= id '(' <opt_arg_separated> ')'
        String signature = "";
        LinkedList<String> parameters = this.getActualParameters((Reduction)reduction.getToken(2).getData());
        String id = (String)reduction.getToken(0).getData();

        signature = id+"(";
        if(parameters.size()>0){
            signature+=parameters.get(0)+",";
            for(int i = 1;i<parameters.size(); i++){
                String a  = parameters.get(i);
                signature+=""+a+",";
            }
            signature = signature.substring(0, signature.length()-1);
        }
        signature+=")";

        return signature;
    }

    /***************************************************************
    * getActualParameters
    * @param reduction
    * @return void
    ***************************************************************/
    private LinkedList<String> getActualParameters(Reduction reduction) {
        //<methodCall> ::= id '(' <opt_arg_separated> ')'
        LinkedList<String> actual_param = new LinkedList<String>();

        switch(reduction.getParentRule().getTableIndex())
        {
            case RuleConstants.RULE_OPT_ARG_SEPARATED:
                //#########################################################################################################
                //<opt_arg_separated> ::= <arg list>
                actual_param.addAll(this.getActualParameters((Reduction)reduction.getToken(0).getData()));
                break;
            case RuleConstants.RULE_OPT_ARG_SEPARATED2:
                //#########################################################################################################
                //<opt_arg_separated> ::=
                break;
            case RuleConstants.RULE_ARGLIST:
                //#########################################################################################################
                //<arg list> ::= <arg>
                actual_param.addAll(this.getActualParameters((Reduction)reduction.getToken(0).getData()));
                break;
            case RuleConstants.RULE_ARGLIST_COMMA:
                //#########################################################################################################
                //<arg list> ::= <arg list> ',' <arg>
                actual_param.addAll(this.getActualParameters((Reduction)reduction.getToken(0).getData()));
                actual_param.addAll(this.getActualParameters((Reduction)reduction.getToken(2).getData()));
                break;
            case RuleConstants.RULE_ARG:
                //#########################################################################################################
                //<arg> ::= <expression>
                String arg = this.obtainType((Reduction)reduction.getToken(0).getData());
                actual_param.add(arg);
                break;
        }
        return actual_param;
    }

    /***************************************************************
    * addMethodDeclarationToTalbe
    * @param reduction
    * @return void
    ***************************************************************/
    private void addMethodDeclarationToTable(Reduction reduction) {
        //<methodDeclaration> ::= <Type> id '(' <opt_parameter> ')' <block>
        //<Type> = <methodType> ::= 'int' | 'char' | 'boolean' | 'void'
        Reduction Type1 = (Reduction)reduction.getToken(0).getData();
        String id = (String)reduction.getToken(1).getData();
        Reduction opt_parameter = (Reduction)reduction.getToken(3).getData();
        Type tipo = null;

        if(Type1.getTokenCount()==1){

            if(Type1.getToken(0).getData() instanceof String){
                String a = (String)Type1.getToken(0).getData();
                if(a.equals("void") || a.equals("int") || a.equals("char") || a.equals("boolean")){
                    //TODO verificar tamaños de los tipos
                    tipo = new Type(a,Type.getBasicTamano(a));
                }
                else{
                    this.addErrorLog("\nMethod type not correct (Line "+reduction.getToken(1).getLineNumber()+"): "+(String)Type1.getToken(0).getData()+"");
                    return;
                }
            }
            else{
                this.addErrorLog("\nMethod type not correct (Line "+reduction.getToken(1).getLineNumber()+"): "+(String)Type1.getToken(0).getData()+"");
                return;
            }
        }
        else{
            this.addErrorLog("\nMethod type not correct (Line "+reduction.getToken(1).getLineNumber()+"): "+(String)Type1.getToken(0).getData()+"");
            return;
        }

        if(id.equals("print")){
            this.addErrorLog("\nCannot use method name (Line "+reduction.getToken(1).getLineNumber()+"): "+"print"+"");
            return;
        }

        //<opt_parameter>
        Scope nuevo = new Scope(this.actual_ambit);
        this.actual_ambit = nuevo;
        this.methodAmbit = true;
        LinkedList<Symbol> parameters = this.getParamList(opt_parameter);
        Method met = new Method(id, tipo, parameters);
        boolean canAdd = this.methodTable.addMethod(met);
        if(canAdd == false){
            this.addErrorLog("\nMethod signature is already defined (Line "+reduction.getToken(1).getLineNumber()+"): "+met.getMethodSignature()+"");
            return;
        }
        this.addDebugLog("New Method declaration (Line "+reduction.getToken(1).getLineNumber()+"): "+met.getMethodSignature()+"\n");
        this.symboltable.addAllSymbol(parameters);
    }

    /***************************************************************
    * createTable
    * recursive method to generate SymbolTable
    * @param reduction
    ***************************************************************/
    private void createTable(Reduction reduction){

        Reduction kleene_declaration;
        Reduction declaration;
        Reduction structDeclaration;
        Reduction varDeclaration;
        Reduction methodDeclaration;
        Reduction kleene_varDeclaration;
        Reduction kleene_statement;
        Reduction statement;
        Reduction block;
        Reduction selection;
        Reduction iteration;
        Reduction opt_else_block;

        switch(reduction.getParentRule().getTableIndex())
        {
            case RuleConstants.RULE_PROGRAM_CLASS_PROGRAM_LBRACE_RBRACE:
                //#########################################################################################################
                //<Program> ::= class Program '{' <kleene_declaration> '}'
                kleene_declaration = (Reduction)reduction.getToken(3).getData();
                this.createTable(kleene_declaration);
                break;
            case RuleConstants.RULE_KLEENE_DECLARATION:
                //#########################################################################################################
                //<kleene_declaration> ::= <declaration> <kleene_declaration>
                declaration = (Reduction)reduction.getToken(0).getData();
                this.createTable(declaration);
                kleene_declaration = (Reduction)reduction.getToken(1).getData();
                this.createTable(kleene_declaration);
                break;
            case RuleConstants.RULE_KLEENE_DECLARATION2:
                //#########################################################################################################
                //<kleene_declaration> ::=
                //stops the recursion...
                break;
            case RuleConstants.RULE_DECLARATION:
                //#########################################################################################################
                //<declaration> ::= <structDeclaration>
                structDeclaration = (Reduction)reduction.getToken(0).getData();
                this.createTable(structDeclaration);
                break;
            case RuleConstants.RULE_DECLARATION2:
                //#########################################################################################################
                //<declaration> ::= <varDeclaration>
                varDeclaration = (Reduction)reduction.getToken(0).getData();
                this.createTable(varDeclaration);
                break;
            case RuleConstants.RULE_DECLARATION3:
                //#########################################################################################################
                //<declaration> ::= <methodDeclaration>
                methodDeclaration = (Reduction)reduction.getToken(0).getData();
                this.createTable(methodDeclaration);
                break;
            case RuleConstants.RULE_KLEENE_VARDECLARATION:
                //#########################################################################################################
                //<kleene_varDeclaration> ::= <varDeclaration> <kleene_varDeclaration>
                varDeclaration = (Reduction)reduction.getToken(0).getData();
                this.createTable(varDeclaration);
                kleene_varDeclaration = (Reduction)reduction.getToken(1).getData();
                this.createTable(kleene_varDeclaration);
                break;
            case RuleConstants.RULE_KLEENE_VARDECLARATION2:
                //#########################################################################################################
                //<kleene_varDeclaration> ::=
                //stop the recursion...
                break;
            case RuleConstants.RULE_VARDECLARATION_ID_SEMI:
                //#########################################################################################################
                //#########################################################################################################
                //<varDeclaration> ::= <Type> id <varDecl 1> ';'//<varDeclaration> ::= <Type> id <varDecl 1> ';'
                System.out.println("varDeclaration");
                this.addVarDeclarationToTable(reduction);
                break;
            case RuleConstants.RULE_STRUCTDECLARATION_STRUCT_ID_LBRACE_RBRACE:
                //#########################################################################################################
                //#########################################################################################################
                //<structDeclaration> ::= struct id '{' <kleene_varDeclaration> '}'
                //no meterse a kleene varDeclaration
                //entra acá cuando sólo se declara (sin ningún declarar ninguna variable de este tipo)
                System.out.println("structDeclaration");
                this.addStructToStructTable(reduction);
                break;
            case RuleConstants.RULE_METHODDECLARATION_ID_LPARAN_RPARAN:
                //#########################################################################################################
                //#########################################################################################################
                //<methodDeclaration> ::= <Type> id '(' <opt_parameter> ')' <block>
                System.out.println("methodDeclaration");
                this.addMethodDeclarationToTable(reduction);
                block = (Reduction)reduction.getToken(5).getData();
                this.createTable(block);

                break;
            case RuleConstants.RULE_TYPE:
                //#########################################################################################################
                //<Type> ::= <structDeclaration>
                structDeclaration = (Reduction)reduction.getToken(0).getData();
                this.createTable(structDeclaration);
                break;
            case RuleConstants.RULE_BLOCK_LBRACE_RBRACE:
                //#########################################################################################################
                //<block> ::= '{' <kleene_varDeclaration> <kleene_statement> '}'
                if(this.methodAmbit == true){
                    //no cambiar de ámbito porque se acaba de definir un método
                    this.methodAmbit = false;
                }
                else{
                    Scope nuevo = new Scope(this.actual_ambit);
                    this.actual_ambit = nuevo;
                }
                kleene_varDeclaration = (Reduction)reduction.getToken(1).getData();
                this.createTable(kleene_varDeclaration);
                kleene_statement = (Reduction)reduction.getToken(2).getData();
                this.createTable(kleene_statement);
                this.actual_ambit = this.actual_ambit.getPrev_scope();
                break;
            case RuleConstants.RULE_KLEENE_STATEMENT:
                //#########################################################################################################
                //<kleene_statement> ::= <statement> <kleene_statement>
                statement = (Reduction)reduction.getToken(0).getData();
                this.createTable(statement);
                kleene_statement = (Reduction)reduction.getToken(1).getData();
                this.createTable(kleene_statement);
                break;
            case RuleConstants.RULE_KLEENE_STATEMENT2:
                //#########################################################################################################
                //<kleene_statement> ::=
                //stop recursion..
                break;
            case RuleConstants.RULE_STATEMENT:
                //#########################################################################################################
                //<statement> ::= <block>
                block = (Reduction)reduction.getToken(0).getData();
                this.createTable(block);
                break;
            case RuleConstants.RULE_STATEMENT2:
                //#########################################################################################################
                //<statement> ::= <selection>
                selection = (Reduction)reduction.getToken(0).getData();
                this.createTable(selection);
                break;
            case RuleConstants.RULE_STATEMENT3:
                //#########################################################################################################
                //<statement> ::= <iteration>
                iteration = (Reduction)reduction.getToken(0).getData();
                this.createTable(iteration);
                break;
            case RuleConstants.RULE_STATEMENT_SEMI:
                //#########################################################################################################
                //<statement> ::= <return> ';'
                break;
            case RuleConstants.RULE_STATEMENT_SEMI2:
                //#########################################################################################################
                //<statement> ::= <assign> ';'
                break;
            case RuleConstants.RULE_STATEMENT_SEMI3:
                //#########################################################################################################
                //<statement> ::= <opt_expression> ';'
                break;
            case RuleConstants.RULE_SELECTION_IF_LPARAN_RPARAN:
                //#########################################################################################################
                //<selection> ::= if '(' <expression> ')' <block> <opt_else_block>
                block = (Reduction)reduction.getToken(4).getData();
                this.createTable(block);
                opt_else_block = (Reduction)reduction.getToken(5).getData();
                this.createTable(opt_else_block);
                break;
            case RuleConstants.RULE_OPT_ELSE_BLOCK_ELSE:
                //#########################################################################################################
                //<opt_else_block> ::= else <block>
                block = (Reduction)reduction.getToken(1).getData();
                this.createTable(block);
                break;
            case RuleConstants.RULE_OPT_ELSE_BLOCK:
                //#########################################################################################################
                //<opt_else_block> ::=
                //stop recursion..
                break;
            case RuleConstants.RULE_ITERATION_WHILE_LPARAN_RPARAN:
                //#########################################################################################################
                //<iteration> ::= while '(' <expression> ')' <block>
                block = (Reduction)reduction.getToken(4).getData();
                this.createTable(block);
                break;
        }
    }

    String type_return_method = "";

    /***************************************************************
    * obtainType
    * recursive method to check the type
    * @param reduction
    ***************************************************************/
    private String obtainType(Reduction reduction){
        String retorno = "";

        String kleene_declaration,declaration,varDeclaration,varDecl_1,structDeclaration,kleene_varDeclaration;
        String methodDeclaration,opt_parameter,parameter_list,Type,parameter,block,kleene_statement,statement;
        String selection,opt_else_block,iteration,ret,assign,opt_expression,expression,Rel_Exp,Add_Exp;
        String Mult_Exp,Negate_Exp,conditionalop,relop,addop,mulop,Value,location,simpleLocation,methodCall;
        String literal;

        Symbol symbol;

        switch(reduction.getParentRule().getTableIndex())
        {
            case RuleConstants.RULE_PROGRAM_CLASS_PROGRAM_LBRACE_RBRACE:
                //#########################################################################################################
                //<Program> ::= class Program '{' <kleene_declaration> '}'
                retorno = this.obtainType((Reduction)reduction.getToken(3).getData());
                break;
            case RuleConstants.RULE_KLEENE_DECLARATION:
                //#########################################################################################################
                //<kleene_declaration> ::= <declaration> <kleene_declaration>
                declaration = this.obtainType((Reduction)reduction.getToken(0).getData());
                kleene_declaration = this.obtainType((Reduction)reduction.getToken(1).getData());
                if(declaration.equals("error") || kleene_declaration.equals("error")){
                    retorno = "error";
                }else{
                    retorno = "void";
                }
                break;
            case RuleConstants.RULE_KLEENE_DECLARATION2:
                //#########################################################################################################
                //<kleene_declaration> ::=
                retorno = "void";
                break;
            case RuleConstants.RULE_DECLARATION:
                //#########################################################################################################
                //<declaration> ::= <structDeclaration>
                retorno = "void"; // ya está validado cuando se crea la tabla
                break;
            case RuleConstants.RULE_DECLARATION2:
                //#########################################################################################################
                //<declaration> ::= <varDeclaration>
                retorno = "void"; // ya está validado cuando se crea la tabla
                break;
            case RuleConstants.RULE_DECLARATION3:
                //#########################################################################################################
                //<declaration> ::= <methodDeclaration>
                methodDeclaration = this.obtainType((Reduction)reduction.getToken(0).getData());
                if(methodDeclaration.equals("error")){
                    retorno ="error";
                }else{
                    retorno = "void";
                }
                break;
            case RuleConstants.RULE_METHODDECLARATION_ID_LPARAN_RPARAN:
                //#########################################################################################################
                //<methodDeclaration> ::= <Type> id '(' <opt_parameter> ')' <block>
                //<Type> ::= int | char | boolean | void
                Reduction red_Type = (Reduction)reduction.getToken(0).getData();
                Type = (String)red_Type.getToken(0).getData();//no debería dar error porque está validado en crearTabla
                this.type_return_method = Type;
                Reduction red_block = (Reduction)reduction.getToken(5).getData();
                block = this.obtainType(red_block);
                if(block.equals("error")){
                    retorno = "error";
                    break;
                }
                //si el tipo de block es diferente a type_return_method significa un missing return statement
                if(type_return_method.equals(block) || type_return_method.equals("void")){
                    retorno = "void";
                }else{
                    retorno = "error";
                    this.addErrorLog("Missing return statement", red_block.getToken(3).getLineNumber(), "\n\t"+"}");
                }
                break;
            case RuleConstants.RULE_BLOCK_LBRACE_RBRACE:
                //#########################################################################################################
                //<block> ::= '{' <kleene_varDeclaration> <kleene_statement> '}'
                this.actual_ambit = this.actual_ambit.getKid();
                //System.out.println("entra a nuevo ámbito: "+this.actual_ambit.getName());
                retorno = this.obtainType((Reduction)reduction.getToken(2).getData());
                //System.out.println("sale del ámbito: "+this.actual_ambit.getName());
                this.actual_ambit = this.actual_ambit.getPrev_scope();
                //System.out.println("regresa al ámbito: "+this.actual_ambit.getName());
                break;
            case RuleConstants.RULE_KLEENE_STATEMENT:
                //#########################################################################################################
                //<kleene_statement> ::= <statement> <kleene_statement>
                //revisar si en <statement> hay algún return.. si hay entonces el <kleene statement> es unreachable
                Reduction red_statement = (Reduction)reduction.getToken(0).getData();
                Reduction red_kleene_statement = (Reduction)reduction.getToken(1).getData();
                
                statement = this.obtainType(red_statement);
                kleene_statement = this.obtainType(red_kleene_statement);

                if(red_statement.getParentRule().getTableIndex() == RuleConstants.RULE_STATEMENT_SEMI){
                    //<statement> ::= <return> ';'
                    if(red_kleene_statement.getTokenCount() != 0){
                        //unreachable statement (Line: 4)
                        this.addErrorLog("unreachable statement"+" (Line "+(red_statement.getToken(1).getLineNumber()+1)+")"+"\n");
                    }
                }else if(red_statement.getParentRule().getTableIndex() == RuleConstants.RULE_STATEMENT2){
                    //<statement> ::= <selection>
                    //<selection> ::= if '(' <expression> ')' <block> <opt_else_block>
                    int opt_else_block_len = ((Reduction)((Reduction)red_statement.getToken(0).getData()).getToken(5).getData()).getTokenCount();
                    if(red_kleene_statement.getTokenCount() != 0 && opt_else_block_len!=0 && statement.equals(this.type_return_method) && this.type_return_method.equals("void")==false){
                        //unreachable statement (Line: 4)
                        Reduction red_selection = (Reduction)red_statement.getToken(0).getData();
                        this.addErrorLog("unreachable statement"+" (Line "+(getLastLineSelection(red_selection)+1)+")"+"\n");
                    }
                }

                if(red_kleene_statement.getTokenCount() == 0){
                    retorno = statement;
                }else{
                    retorno = kleene_statement;
                }
                break;
            case RuleConstants.RULE_KLEENE_STATEMENT2:
                //#########################################################################################################
                //<kleene_statement> ::=
                retorno = "void";
                break;
            case RuleConstants.RULE_STATEMENT:
                //#########################################################################################################
                //<statement> ::= <block>
                retorno = this.obtainType((Reduction)reduction.getToken(0).getData());
                break;
            case RuleConstants.RULE_STATEMENT2:
                //#########################################################################################################
                //<statement> ::= <selection>
                retorno = this.obtainType((Reduction)reduction.getToken(0).getData());
                break;
            case RuleConstants.RULE_STATEMENT3:
                //#########################################################################################################
                //<statement> ::= <iteration>
                retorno = this.obtainType((Reduction)reduction.getToken(0).getData());
                break;
            case RuleConstants.RULE_STATEMENT_SEMI:
                //#########################################################################################################
                //<statement> ::= <return> ';'
                retorno = this.obtainType((Reduction)reduction.getToken(0).getData());
                break;
            case RuleConstants.RULE_STATEMENT_SEMI2:
                //#########################################################################################################
                //<statement> ::= <assign> ';'
                retorno = this.obtainType((Reduction)reduction.getToken(0).getData());
                break;
            case RuleConstants.RULE_STATEMENT_SEMI3:
                //#########################################################################################################
                //<statement> ::= <opt_expression> ';'
                retorno = this.obtainType((Reduction)reduction.getToken(0).getData());
                break;
            case RuleConstants.RULE_SELECTION_IF_LPARAN_RPARAN:
                //#########################################################################################################
                //<selection> ::= if '(' <expression> ')' <block> <opt_else_block>

                expression = this.obtainType((Reduction)reduction.getToken(2).getData());
                if(expression.equals("boolean")==false){
                    retorno = "error";
                    this.addErrorLog("Incompatible types", reduction.getToken(2).getLineNumber() , "\n\t"+"found: "+expression+"\n\t"+"required: "+"boolean");
                    //break;//TODO ver si quitar este break de <selection>
                }
                block = this.obtainType((Reduction)reduction.getToken(4).getData());
                opt_else_block = this.obtainType((Reduction)reduction.getToken(5).getData());
                if(block.equals("error") || opt_else_block.equals("error")){
                    retorno = "error";
                    break;
                }
                if(block.equals(opt_else_block)){
                    retorno = block;
                }else if(((Reduction)reduction.getToken(5).getData()).getTokenCount() == 0){
                    retorno = "void";//TODO ver si regresar esto a block
                }else{
                    retorno = "void";//los retornos no son iguales, entonces el if no devuelve nada
                }
                break;
            case RuleConstants.RULE_OPT_ELSE_BLOCK_ELSE:
                //#########################################################################################################
                //<opt_else_block> ::= else <block>
                retorno = this.obtainType((Reduction)reduction.getToken(1).getData());
                break;
            case RuleConstants.RULE_OPT_ELSE_BLOCK:
                //#########################################################################################################
                //<opt_else_block> ::=
                retorno = "void";
                break;
            case RuleConstants.RULE_ITERATION_WHILE_LPARAN_RPARAN:
                //#########################################################################################################
                //<iteration> ::= while '(' <expression> ')' <block>

                expression = this.obtainType((Reduction)reduction.getToken(2).getData());
                if(expression.equals("boolean")==false){
                    retorno = "error";
                    this.addErrorLog("Incompatible types", reduction.getToken(2).getLineNumber() , "\n\t"+"found: "+expression+"\n\t"+"required: "+"boolean");
                    //break;//TODO ver si quitar este break de <iteration>
                }
                block = this.obtainType((Reduction)reduction.getToken(4).getData());
                if(block.equals("error")){
                    retorno = "error";
                }else{
                    retorno = "void";//void porque en un while no se garantiza nunca regresar algo
                }

                break;
            case RuleConstants.RULE_RETURN_RETURN:
                //#########################################################################################################
                //<return> ::= return <opt_expression>

                opt_expression = this.obtainType((Reduction)reduction.getToken(1).getData());
                if(type_return_method.equals(opt_expression)){
                    retorno = type_return_method;
                }else{//El retorno debe de ser del mismo tipo de la declaración del método
                    retorno = "error";
                    this.addErrorLog("Incompatible types in return", reduction.getToken(0).getLineNumber() , "\n\t"+"found: "+opt_expression+"\n\t"+"required: "+type_return_method+"");
                }

                break;
            case RuleConstants.RULE_ASSIGN_EQ:
                //#########################################################################################################
                //<assign> ::= <location> '=' <expression>

                location = this.obtainType((Reduction)reduction.getToken(0).getData());
                expression = this.obtainType((Reduction)reduction.getToken(2).getData());

                if(location.equals("error") || expression.equals("error")){
                    retorno = "error";
                    break;
                }

                if(location.equals(expression)){
                    retorno = "void";
                }else{
                    System.out.println("tipos incompatibles en assign");
                    this.addErrorLog("Incompatible types in assign", reduction.getToken(1).getLineNumber() , "\n\t"+"found: "+expression+"\n\t"+"required: "+location+"");
                    retorno = "error";
                }

                break;
            case RuleConstants.RULE_OPT_EXPRESSION:
                //#########################################################################################################
                //<opt_expression> ::= <expression>
                retorno = this.obtainType((Reduction)reduction.getToken(0).getData());
                break;
            case RuleConstants.RULE_OPT_EXPRESSION2:
                //#########################################################################################################
                //<opt_expression> ::=
                retorno = "void";
                break;
            case RuleConstants.RULE_EXPRESSION:
                //#########################################################################################################
                //<expression> ::= <Rel Exp> <conditionalop> <expression>

                Rel_Exp = this.obtainType((Reduction)reduction.getToken(0).getData());
                expression = this.obtainType((Reduction)reduction.getToken(2).getData());
                String str_conditionalop = (String)((Reduction)reduction.getToken(1).getData()).getToken(0).getData();
                if(Rel_Exp.equals("error") ||expression.equals("error")){
                    retorno = "error";
                }
                else if(Rel_Exp.equals("boolean") && expression.equals("boolean")) {
                    retorno = "boolean";
                }else{
                    retorno = "error";
                    this.addErrorLog("operator "+str_conditionalop+" cannot be applied", reduction.getToken(1).getLineNumber() , "\n\t"+"to "+Rel_Exp+", "+expression+"");
                }

                break;
            case RuleConstants.RULE_EXPRESSION2:
                //#########################################################################################################
                //<expression> ::= <Rel Exp>
                retorno = this.obtainType((Reduction)reduction.getToken(0).getData());
                break;
            case RuleConstants.RULE_RELEXP:
                //#########################################################################################################
                //<Rel Exp> ::= <Add Exp> <relop> <Rel Exp>

                //<relop> ::= '<=' | '<' | '>' | '>=' | '==' | '!='
                Reduction relop_op = (Reduction)reduction.getToken(1).getData();
                String str_relop = (String)relop_op.getToken(0).getData();

                Add_Exp = this.obtainType((Reduction)reduction.getToken(0).getData());
                Rel_Exp = this.obtainType((Reduction)reduction.getToken(2).getData());

                if(Add_Exp.equals("error") || Rel_Exp.equals("error")){
                    retorno = "error";
                    break;
                }

                if(str_relop.equals("!=") || str_relop.equals("==")){
                    //ambos iguales (int | char | boolean) -> boolean else error
                    if(Add_Exp.equals(Rel_Exp) && (Add_Exp.equals("int") || Add_Exp.equals("char") || Add_Exp.equals("boolean"))){
                        retorno = "boolean";
                    }else{
                        this.addErrorLog("operator "+str_relop+" cannot be applied", relop_op.getToken(0).getLineNumber() , "\n\t"+"to "+Add_Exp+", "+Rel_Exp+"");
                        retorno = "error";
                    }

                }else if(str_relop.equals("<") || str_relop.equals("<=") || str_relop.equals(">") || str_relop.equals(">=")){
                    //deben ser de tipo int
                    //si ambos son de tipo int, resultado es boolean else error
                    if(Add_Exp.equals("int") && Rel_Exp.equals("int") ){
                        retorno = "boolean";
                    }else{
                        this.addErrorLog("operator "+str_relop+" cannot be applied", relop_op.getToken(0).getLineNumber() , "\n\t"+"to "+Add_Exp+", "+Rel_Exp+"");
                        retorno = "error";
                    }
                }

                break;
            case RuleConstants.RULE_RELEXP2:
                //#########################################################################################################
                //<Rel Exp> ::= <Add Exp>
                retorno = this.obtainType((Reduction)reduction.getToken(0).getData());
                break;
            case RuleConstants.RULE_ADDEXP:
                //#########################################################################################################
                //<Add Exp> ::= <Mult Exp> <addop> <Add Exp>

                Mult_Exp = this.obtainType((Reduction)reduction.getToken(0).getData());
                Add_Exp = this.obtainType((Reduction)reduction.getToken(2).getData());
                if(Add_Exp.equals("error") || Mult_Exp.equals("error")){
                    retorno = "error";
                    break;
                }

                Reduction add_op = (Reduction)reduction.getToken(1).getData();
                String str_addop = (String)add_op.getToken(0).getData();

                if(Mult_Exp.equals("int") && Add_Exp.equals("int") ){
                    retorno = "int";
                }else{
                    this.addErrorLog("operator "+str_addop+" cannot be applied", add_op.getToken(0).getLineNumber() , "\n\t"+"to "+Mult_Exp+", "+Add_Exp+"");
                    retorno = "error";
                }

                break;
            case RuleConstants.RULE_ADDEXP2:
                //#########################################################################################################
                //<Add Exp> ::= <Mult Exp>
                retorno = this.obtainType((Reduction)reduction.getToken(0).getData());
                break;
            case RuleConstants.RULE_MULTEXP:
                //#########################################################################################################
                //<Mult Exp> ::= <Negate Exp> <mulop> <Mult Exp>

                Negate_Exp = this.obtainType((Reduction)reduction.getToken(0).getData());
                Mult_Exp = this.obtainType((Reduction)reduction.getToken(2).getData());

                if(Negate_Exp.equals("error") || Mult_Exp.equals("error")){
                    retorno = "error";
                    break;
                }

                Reduction mul_op = (Reduction)reduction.getToken(1).getData();
                String str_mulop = (String)mul_op.getToken(0).getData();

                if(Negate_Exp.equals("int") && Mult_Exp.equals("int")){
                    retorno = "int";
                }else{
                    this.addErrorLog("operator "+str_mulop+" cannot be applied", mul_op.getToken(0).getLineNumber() , "\n\t"+"to "+Negate_Exp+", "+Mult_Exp+"");
                    retorno = "error";
                }

                break;
            case RuleConstants.RULE_MULTEXP2:
                //#########################################################################################################
                //<Mult Exp> ::= <Negate Exp>
                retorno = this.obtainType((Reduction)reduction.getToken(0).getData());
                break;
            case RuleConstants.RULE_NEGATEEXP_MINUS:
                //#########################################################################################################
                //<Negate Exp> ::= '-' <Value>

                Value = this.obtainType((Reduction)reduction.getToken(1).getData());
                if(Value.equals("error")){
                    retorno = "error";
                    break;
                }
                if(Value.equals("int")){
                    retorno = "int";
                }else{
                    this.addErrorLog("operator "+"-"+" cannot be applied", reduction.getToken(0).getLineNumber() , "\n\t"+"to "+Value+"");
                    retorno = "error";
                }

                break;
            case RuleConstants.RULE_NEGATEEXP_EXCLAM:
                //#########################################################################################################
                //<Negate Exp> ::= '!' <Value>

                Value = this.obtainType((Reduction)reduction.getToken(1).getData());
                if(Value.equals("error")){
                    retorno = "error";
                    break;
                }
                if(Value.equals("boolean")){
                    retorno = "boolean";
                }else{
                    this.addErrorLog("operator "+"!"+" cannot be applied", reduction.getToken(0).getLineNumber() , "\n\t"+"to "+Value+"");
                    retorno = "error";
                }

                break;
            case RuleConstants.RULE_NEGATEEXP:
                //#########################################################################################################
                //<Negate Exp> ::= <Value>
                retorno = this.obtainType((Reduction)reduction.getToken(0).getData());
                break;
            case RuleConstants.RULE_VALUE:
                //#########################################################################################################
                //<Value> ::= <literal>
                retorno = this.obtainType((Reduction)reduction.getToken(0).getData());
                break;
            case RuleConstants.RULE_VALUE_LPARAN_RPARAN:
                //#########################################################################################################
                //<Value> ::= '(' <expression> ')'
                retorno = this.obtainType((Reduction)reduction.getToken(1).getData());
                break;
            case RuleConstants.RULE_VALUE2:
                //#########################################################################################################
                //<Value> ::= <methodCall>
                retorno = this.obtainType((Reduction)reduction.getToken(0).getData());
                break;
            case RuleConstants.RULE_VALUE3:
                //#########################################################################################################
                //<Value> ::= <location>
                retorno = this.obtainType((Reduction)reduction.getToken(0).getData());
                break;
            case RuleConstants.RULE_LOCATION_DOT:
                //*********************************************************************************************************
                //<location> ::= <simpleLocation> '.' <location>

                //obtener a simpleLocation
                simpleLocation = this.obtainType((Reduction)reduction.getToken(0).getData());
                
                if(simpleLocation.equals("error")){
                    retorno = "error";
                    break;
                }

                String id_location_1 = (String)((Reduction)reduction.getToken(0).getData()).getToken(0).getData();

                //revisar si es un struct (empieza con "struct:")
                if(!simpleLocation.startsWith("struct:")){
                    retorno = "error";
                    this.addErrorLog("cannot apply <simpleLocation> '.' <location>", reduction.getToken(1).getLineNumber() , "\n\t"+""+id_location_1+" is not a struture"+"\n\tfound: "+simpleLocation);
                    break;
                }
                
                if(simpleLocation.endsWith("[]")){
                    retorno = "error";
                    this.addErrorLog("cannot apply <simpleLocation> '.' <location>", reduction.getToken(1).getLineNumber() , "\n\t"+""+id_location_1+" is not a struture, is an array of structure"+"\n\tfound: "+simpleLocation);
                    break;
                }

                //buscarlo en la tabla de símbolos
                symbol = this.symboltable.getSymbol(id_location_1, actual_ambit);
                retorno = this.getTypeLocation((Reduction)reduction.getToken(2).getData(), symbol.getType().getMembers());
                break;
            case RuleConstants.RULE_LOCATION:
                //*********************************************************************************************************
                //<location> ::= <simpleLocation>
                retorno = this.obtainType((Reduction)reduction.getToken(0).getData());
                break;
            case RuleConstants.RULE_SIMPLELOCATION_ID_LBRACKET_RBRACKET:
                //*********************************************************************************************************
                //<simpleLocation> ::= id '[' <expression> ']'

                //primero revisar que <expression> sea de tipo int
                expression = this.obtainType((Reduction)reduction.getToken(2).getData());

                if(expression.equals("error")){
                    retorno = "error";
                    break;
                }else if(!expression.equals("int")){
                    retorno = "error";
                    this.addErrorLog("Incompatible types in the index of [num]", reduction.getToken(1).getLineNumber() , "\n\t"+"found: "+expression+"\n\t"+"required: "+"int");
                    System.out.println("tipo incompatible.... [!int]");
                    //break;//TODO ver si es necesario ponerlo...
                }

                String id_simpleLocation_2 = (String)reduction.getToken(0).getData();
                symbol = this.symboltable.getSymbol(id_simpleLocation_2, actual_ambit);
                if(symbol == null){
                    //no encontró en la tabla de símbolos
                    //cannot find symbol (Line 2): a
                    this.addErrorLog("cannot find symbol", reduction.getToken(0).getLineNumber() , "\n\t"+""+id_simpleLocation_2);
                    retorno = "error";
                }else{
                    //revisar si el símbolo es un arreglo.. si es quitar el final "[]" si no es -> error
                    if(symbol.getType().isArray()){
                        retorno = symbol.getType().getType_name().substring(0, symbol.getType().getType_name().length()-2);
                    }else{
                        this.addErrorLog("cannot apply [<expression>]", reduction.getToken(0).getLineNumber() , "\n\t"+""+id_simpleLocation_2+" is not an array"+"\n\t"+"array required, but "+symbol.getType().getType_name()+" found");
                        retorno = "error";
                    }
                }

                break;
            case RuleConstants.RULE_SIMPLELOCATION_ID:
                //*********************************************************************************************************
                //<simpleLocation> ::= id

                String id_simpleLocation_1 = (String)reduction.getToken(0).getData();
                symbol = this.symboltable.getSymbol(id_simpleLocation_1, actual_ambit);
                if(symbol == null){
                    //no encontró en la tabla de símbolos
                    //cannot find symbol (Line 2): a
                    this.addErrorLog("cannot find symbol", reduction.getToken(0).getLineNumber() , "\n\t"+""+id_simpleLocation_1);
                    retorno = "error";
                }else{
                    retorno = symbol.getType().getType_name();
                }

                break;
            case RuleConstants.RULE_METHODCALL_ID_LPARAN_RPARAN:
                //#########################################################################################################
                //<methodCall> ::= id '(' <opt_arg_separated> ')'
                
                //obtener la firma de esta llamada a método y buscarla en la tabla de métodos
                String signature = getMethodCallSignature(reduction);
                //por si los argumentos ya tienen un error...
                if(signature.contains("error") && !signature.startsWith("error")){
                    retorno = "error";
                    break;
                }

                Method correct_method = this.methodTable.getMethod(signature);
                if(correct_method!=null && !signature.isEmpty()){
                    retorno = correct_method.getRet().getType_name();
                }else{
                    //cannot find symbol method (Line 2): method(boolean,int)
                    this.addErrorLog("cannot find method symbol", reduction.getToken(1).getLineNumber() , "\n\t"+signature);
                    retorno = "error";
                }

                break;
            case RuleConstants.RULE_LITERAL:
                //#########################################################################################################
                //<literal> ::= <int_literal>
                //<int_literal> ::= num
                retorno = "int";
                break;
            case RuleConstants.RULE_LITERAL2:
                //#########################################################################################################
                //<literal> ::= <char_literal>
                //<char_literal> ::= character
                retorno = "char";
                break;
            case RuleConstants.RULE_LITERAL3:
                //#########################################################################################################
                //<literal> ::= <bool_literal>
                //<bool_literal> ::= true | false
                retorno = "boolean";
                break;
        }
        return retorno;
    }

    /*****************************************
     * containsMainMethod
     * check if the main method is defined
     *****************************************/
    private int getLastLineSelection(Reduction reduction){
        int line = 0;
        //<selection> ::= if '(' <expression> ')' <block> <opt_else_block>
        Reduction block, opt_else_block;
        switch(reduction.getParentRule().getTableIndex())
        {
            case RuleConstants.RULE_SELECTION_IF_LPARAN_RPARAN:
                //#########################################################################################################
                //<selection> ::= if '(' <expression> ')' <block> <opt_else_block>
                opt_else_block = (Reduction)reduction.getToken(5).getData();
                block = (Reduction)reduction.getToken(4).getData();

                if(opt_else_block.getTokenCount()==0){
                    line = getLastLineSelection(block);
                }else{
                    line = getLastLineSelection(opt_else_block);
                }
                break;
            case RuleConstants.RULE_OPT_ELSE_BLOCK_ELSE:
                //#########################################################################################################
                //<opt_else_block> ::= else <block>
                line = getLastLineSelection((Reduction)reduction.getToken(1).getData());
                break;
            case RuleConstants.RULE_BLOCK_LBRACE_RBRACE:
                //#########################################################################################################
                //<block> ::= '{' <kleene_varDeclaration> <kleene_statement> '}'
                line = reduction.getToken(3).getLineNumber();
                break;

        }
        return line;
    }

    /*****************************************
     * getTypeLocation
     * @return String with the type
     * @param reduction
     * @param members
     *****************************************/
    private String getTypeLocation(Reduction reduction, LinkedList<Symbol> members){
        String retorno = "";

        switch(reduction.getParentRule().getTableIndex())
        {
            case RuleConstants.RULE_LOCATION_DOT:
                //---------------------------------------------------------------------------------------------------------
                //<location> ::= <simpleLocation> '.' <location>

                String simpleLocation = this.getTypeLocation((Reduction)reduction.getToken(0).getData(), members);

                if(simpleLocation.equals("error")){
                    retorno = "error";
                    break;
                }

                String id_location_1 = (String)((Reduction)reduction.getToken(0).getData()).getToken(0).getData();

                //revisar si es un struct (empieza con "struct:")
                if(!simpleLocation.startsWith("struct:")){
                    retorno = "error";
                    this.addErrorLog("cannot apply <simpleLocation> '.' <location>", reduction.getToken(1).getLineNumber() , "\n\t"+""+id_location_1+" is not a struture"+"\n\tfound: "+simpleLocation);
                    break;
                }

                if(simpleLocation.endsWith("[]")){
                    retorno = "error";
                    this.addErrorLog("cannot apply <simpleLocation> '.' <location>", reduction.getToken(1).getLineNumber() , "\n\t"+""+id_location_1+" is not a struture, is an array of structure"+"\n\tfound: "+simpleLocation);
                    break;
                }

                //buscarlo entre los miembros
                Symbol symbol_0 = this.getLocation_in_Member(id_location_1, members);
                retorno = this.getTypeLocation((Reduction)reduction.getToken(2).getData(), symbol_0.getType().getMembers());
                break;
            case RuleConstants.RULE_LOCATION:
                //---------------------------------------------------------------------------------------------------------
                //<location> ::= <simpleLocation>
                retorno = this.getTypeLocation((Reduction)reduction.getToken(0).getData(), members);
                break;
            case RuleConstants.RULE_SIMPLELOCATION_ID_LBRACKET_RBRACKET:
                //---------------------------------------------------------------------------------------------------------
                //<simpleLocation> ::= id '[' <expression> ']'

                String expression = this.obtainType((Reduction)reduction.getToken(2).getData());
                if(expression.equals("error")){
                    retorno = "error";
                    break;
                }
                else if(!expression.equals("int")) {
                    retorno = "error";
                    this.addErrorLog("Incompatible types", reduction.getToken(1).getLineNumber() , "\n\t"+"found: "+expression+"\n\t"+"required: "+"int");
                    break;
                }
                String id_2 = (String)reduction.getToken(0).getData();
                Boolean exist_2 = this.existLocation_in_Member(id_2, members);
                if(exist_2){
                    Symbol symbol_2 = this.getLocation_in_Member(id_2, members);
                    if(symbol_2.getType().isArray()){
                        //quitar el "[]" del final...
                        retorno = symbol_2.getType().getType_name().substring(0, symbol_2.getType().getType_name().length()-2);
                    }else{
                        retorno = "error";
                        this.addErrorLog("cannot apply [<expression>]", reduction.getToken(1).getLineNumber() , "\n\t"+""+id_2+" is not an array"+"\n\t"+"array required, but "+symbol_2.getType().getType_name()+" found");
                    }
                }else{
                    retorno = "error";
                    this.addErrorLog("cannot find symbol", reduction.getToken(0).getLineNumber() , "\n\t"+"Symbol "+id_2+" is not in member's struture");
                }

                break;
            case RuleConstants.RULE_SIMPLELOCATION_ID:
                //---------------------------------------------------------------------------------------------------------
                //<simpleLocation> ::= id
                String id = (String)reduction.getToken(0).getData();
                Boolean exist = this.existLocation_in_Member(id, members);
                if(exist){
                    Symbol symbol = this.getLocation_in_Member(id, members);
                    retorno = symbol.getType().getType_name();
                }else{
                    retorno = "error";
                    this.addErrorLog("cannot find symbol", reduction.getToken(0).getLineNumber() , "\n\t"+"Symbol "+id+" is not in member's struture");
                }
                break;
        }


        return retorno;
    }

    /*****************************************
     * getTypeLocation
     * @return String with the type
     * @param reduction
     * @param members
     *****************************************/

    private int generateInterCode(Reduction reduction, int cont){

        int retorno = cont;

        switch(reduction.getParentRule().getTableIndex())
        {
            case RuleConstants.RULE_PROGRAM_CLASS_PROGRAM_LBRACE_RBRACE:
                //#########################################################################################################
                //<Program> ::= class Program '{' <kleene_declaration> '}'
                generateInterCode((Reduction)reduction.getToken(3).getData(),cont);
                break;
            case RuleConstants.RULE_KLEENE_DECLARATION:
                //#########################################################################################################
                //<kleene_declaration> ::= <declaration> <kleene_declaration>
                int cont2 = generateInterCode((Reduction)reduction.getToken(0).getData(),cont);
                retorno = generateInterCode((Reduction)reduction.getToken(1).getData(),cont2);
                break;
            case RuleConstants.RULE_DECLARATION3:
                //#########################################################################################################
                //<declaration> ::= <methodDeclaration>
                //<methodDeclaration> ::= <Type> id '(' <opt_parameter> ')' <block>


                Method met = this.methodTable.getMethodList().get(cont);
                Reduction methodDeclaration = (Reduction)reduction.getToken(0).getData();
                Scope ambito_metodo = this.actual_ambit.getKid();

                System.out.println("************************************************************");
                System.out.println("Método: "+met.getMethodSignature()+" subname: "+met.getSubname()+" - Scope: "+ambito_metodo.getName());
                System.out.println("************************************************************");


                MethodInterCodeGen method_code = new MethodInterCodeGen(met, ambito_metodo, methodDeclaration,this);
                method_code.generate();
                this.inter_code.addAll(method_code.getCode());
                this.method_inter_code.add(method_code);

                retorno++;
                break;
        }
        return retorno;
    }

    /*****************************************
     * getInterCode
     * @return the code from the method
     *****************************************/
    public LinkedList<Cod3Dir> getInterCode(){
        return this.inter_code;
    }

    /*****************************************
     * getInterCode
     * @return the code from the method
     *****************************************/
    public LinkedList<AsmCode> getAsmCode(){
        return this.asm_code;
    }

    /*****************************************
     * getAsmCode
     * @return the code from the method
     *****************************************/
    public LinkedList<String> getAsmCodeStr(){
        LinkedList<String> retorno = new LinkedList<String>();
        for(AsmCode a : this.asm_code){
            retorno.add(a.getCode()+"");
        }
        return retorno;
    }

    /*****************************************
     * getInterCode
     * @return the code from the method
     *****************************************/
    public LinkedList<String> getInterCodeStr(){
        LinkedList<String> retorno = new LinkedList<String>();
        for(Cod3Dir a : this.inter_code){
            retorno.add(a.getCodeString()+"");
        }
        return retorno;
    }

    /*****************************************
     * createDefaultMethods
     *****************************************/
    private void createDefaultMethods() {


        Type tipo = new Type("int",Type.getBasicTamano("int"));
        tipo.setParam(true);

        Symbol param = new Symbol("num", tipo, null);
        LinkedList<Symbol> params = new LinkedList<Symbol>();
        params.add(param);
        Method met = new Method("print", new Type("void",0), params);

        met.tam_datos_locales=0;
        met.tam_dir_ret=2;
        met.tam_parametros=2;
        met.tam_temporales=0;
        met.tam_val_ret=0;

        this.methodTable.addMethod(met);
        
    }

    /*****************************************
     * containsMainMethod
     * check if the main method is defined
     *****************************************/
    private void containsMainMethod(){
        String signature = "main()";
        Method correct_method = this.methodTable.getMethod(signature);
        if(correct_method==null){
            //cannot find symbol method (Line 2): method(boolean,int)
            this.addErrorLog("No such method error"+"\n\t"+signature+" is not defined");
        }
    }

    /***************************************************************
     * This class will run the engine, and needs a file called config.dat
     * in the current directory. This file should contain two lines,
     * The first should be the absolute path name to the .cgt file, the second
     * should be the source file you wish to parse.
     * @param args Array of arguments.
    ***************************************************************/
    public void Parse(String textToParse){

        this.textToParse = textToParse;

        All();
        
        try{
            if(this.error == false){

                //System.out.println("parser.currentReduction(): "+parser.currentReduction());
                //System.out.println("root: "+getRoot());
                //System.out.println("arbol: "+this.arbol);
                //println("****************************************************");
                showTree( this.arbol, getRoot(), parser.currentReduction());
                //println("****************************************************");
                //println("****************************************************");

                //crea la tabla de símbolos
                this.createTable(parser.currentReduction());


                if(error == true){
                    parser.closeFile();
                    return;
                }
                createDefaultMethods();

                //verificación de tipos
                String tipo_de_todo = "";
                tipo_de_todo = this.obtainType(parser.currentReduction());
                System.out.println("el tipo de todo el programa es: "+tipo_de_todo);
                //println("Method Table: \n"+this.methodTable.toString());
                println("****************************************************");
                //println("Struct Table: \n"+this.structTable.toString());
                println("****************************************************");

                //verificación de método main
                containsMainMethod();



                if(error == true){
                    parser.closeFile();
                    return;
                }

                //setear el ámbito como el ámbito padre
                this.actual_ambit = this.actual_ambit.getFather();
                //resetear para obtener hijo
                this.actual_ambit.resetGetKid();


                inter_code.add(new InterComentario("*******************************************"));
                inter_code.add(new InterComentario("               Ámbito global"));
                for(decaf.Symbol a : this.getSymbolTable().getAllGlobalSymbol(actual_ambit)){
                    String [] b = MethodInterCodeGen.getDesplazamientoSimple(a,this,this.actual_ambit);
                    inter_code.add(new InterComentario(a.getId()+" = "+b[0]+"["+b[1]+"]"));
                }
                inter_code.add(new InterComentario("*******************************************\n\n"));


                //generación de código intermedio
                generateInterCode(parser.currentReduction(),0);


                //generar código métodos
                AsmCodeGen cod_asm = new AsmCodeGen(this.method_inter_code);
                cod_asm.generate();
                asm_code.addAll(cod_asm.getCode());
                
                

            }
            parser.closeFile();
        }
        catch(ParserException parse){

            println("**PARSER ERROR**\n" + "parse.toString()");
            this.addErrorLog("** PARSER ERROR ** "+"\n\t"+ parse.toString() +"\n");
        }
    }

    /*****************************************
     * @param string
     * @return void
     *****************************************/
    public void addErrorLog(String string) {
        this.error = true;
        this.error_log+=string;
    }

    /*****************************************
     * @param string
     * @return void
     *****************************************/
    public void addErrorLog(String msj, int line, String msj2) {
        this.error = true;
        this.error_log+=msj+" (Line: "+line+"): "+msj2+"\n";
    }

    /*****************************************
     * @param string
     * @return void
     *****************************************/
    public void addOutputLog(String string) {
        this.output_log+=string;
    }

    /*****************************************
     * @param string
     * @return void
     *****************************************/
    public void addDebugLog(String string) {
        this.debug_log+=string;
    }

    /*****************************************
     * @return the grammar
     *****************************************/
    public static String getGrammar() {
        return grammar;
    }
    
    /*****************************************
     * println
     * @param string
     * print the content of string if print is true
     *****************************************/
    private static void println(String string) {
        if(print)
            System.out.println(string);
    }

    private String textToParse = "";
    //**************************************************************************
    private static final String compiledGrammar = "src/Grammar/Decaf_grammar6.cgt";
    private static final String grammar = "src/Grammar/Decaf_grammar6.grm";
    //**************************************************************************
    private DefaultMutableTreeNode root = new DefaultMutableTreeNode("Program");
    private DefaultTreeModel arbol = new DefaultTreeModel(root);
    private JTree jtree = new JTree(this.arbol);
    //**************************************************************************
    private GOLDParser parser = new GOLDParser();
    //**************************************************************************
    private String  method_print = "print";
    //**************************************************************************
    private boolean error = false;
    private String error_log = "";
    private String debug_log = "";
    private String output_log = "";
    //**************************************************************************
    private SymbolTable symboltable = new SymbolTable();
    private MethodTable methodTable = new MethodTable();
    private StructTable structTable = new StructTable();
    private Scope actual_ambit = new Scope();
    private boolean methodAmbit = false;
    private LinkedList<Cod3Dir> inter_code = new LinkedList<Cod3Dir>();
    private LinkedList<AsmCode> asm_code = new LinkedList<AsmCode>();
    private LinkedList<interCodeGen.MethodInterCodeGen> method_inter_code = new LinkedList<interCodeGen.MethodInterCodeGen>();
    //**************************************************************************
    private static boolean print = true;

}